home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / Sherlock 2.0 / DevLibSrc / Main_DevLib / LIBobj.c < prev    next >
Text File  |  1995-11-16  |  16KB  |  717 lines

  1. /*
  2.     devlib: Memory allocation routines.
  3.  
  4.     source:  LIBobj.c
  5.     started: November 4, 1993.
  6.     version:
  7.         November 7, 1995.
  8.             Replace sprintf with cvt_l2s.
  9.         February 25, 1995.
  10.             Removed spurious code from obj_check_fill
  11.         December 26, 1993.
  12.             Bug fix: change obj_find_type to correctly alphabetize types.
  13.             Added variable width columns in obj_dump_stats.
  14.         December 9, 1993.
  15.             Added obj_max_tag_size logic.
  16.         November 6, 1993.
  17.             Bug fix (!) to obj_find_type.
  18.             Commented out obj_free.
  19. */
  20. #include <LIBlib.h>
  21.  
  22. #include <LIBend.h>
  23. #include <LIBenv.h>
  24. #include <LIBmem.h>
  25. #include <LIBobj.h>
  26.  
  27. #include <stdlib.h>
  28. #include <string.h>
  29.  
  30. #define PRODUCTION_TRACE
  31. #undef  PRODUCTION_TRACE
  32.  
  33. #ifdef TURBOC
  34.     #include <alloc.h>
  35. #endif
  36.  
  37. #ifdef MICRO_SOFT
  38.     #include <malloc.h>
  39. #endif
  40.  
  41.     /*
  42.         Only obj_new() is defined in the production version.
  43.     */
  44.  
  45. #ifndef PRODUCTION
  46.  
  47. /*
  48.     Convert an object pointer to a header pointer.
  49. */
  50. #define p2h(p) ((obj_head *) (((char *) p) - sizeof(obj_head)))
  51.  
  52. /*
  53.     Define the list of all objects.
  54.     This list is kept in reverse allocation order.
  55.     The obj_olist field of obj_head_struct holds the links of this list.
  56. */
  57. static obj_head * obj_all;
  58.  
  59. /*
  60.     Define global cumulative statistics.
  61. */
  62. static long obj_ntypes;                /* Number of types. */
  63. static long obj_num_strcmp = 0;        /* Number of calls to strcmp in obj_find_type. */
  64. static size_t obj_max_tag_size = 0;    /* Length of longest type tag. */
  65.  
  66. static long    obj_nmax;                /* Object size statistics. */
  67. static long    obj_nnet;
  68. static long    obj_ntot;
  69.  
  70. static long    obj_cmax;                /* Alloc/free (call) statistics. */
  71. static long    obj_cnet;
  72. static long    obj_ctot;
  73.  
  74. /*
  75.     Define the alphabetical list of type descriptors.
  76.     The type_alpha field of the type descriptor holds the links of this list.
  77. */
  78. static type_des * obj_alpha = NULL;
  79.  
  80. /*
  81.     Prototypes of internal routines.
  82. */
  83. static void            obj_check_fill        (char *p, long n, char * dtag);
  84. static void            obj_dump_fill        (char *p, int n, char * message);
  85. static void            obj_dump_header        (obj_head *h, char * pad_string);
  86. static void         obj_dump_obj_header    (void *p,   char * pad_string);
  87. static type_des *    obj_find_type        (char * tag);
  88. static void            obj_free_check        (void * obj);
  89.  
  90. /*
  91.     Check the list of all known objects for consistency.
  92. */
  93. void
  94. obj_check_all(void)
  95. {
  96.     FTAG("obj_check_all");
  97.     type_des * t;
  98.     obj_head * h;
  99.     STATB(ftag);
  100.  
  101.     for (t = obj_alpha; t != NULL; t = t -> type_alpha) {
  102.  
  103.         int attrib = t -> type_attrib;
  104.         long sum = 0;
  105.         int number = 0;
  106.  
  107.         for (h = t -> type_tlist; h != NULL; h = h -> obj_tlist) {
  108.             obj_check_fill( ((char *) h + sizeof(obj_head)),
  109.                 h -> obj_size, h -> obj_dtag);
  110.             sum += h -> obj_size;
  111.             number++;
  112.         }
  113.  
  114.         ASSERT_TRACE(sum == t -> type_nnet,
  115.             es(ftag); es(":"); es(current_ftag); es(" :type: "); es(t -> type_name);
  116.             enl();
  117.             es("sum: "); elong(sum);
  118.             es(" != type_nnet: "); elong(t -> type_nnet);
  119.         );
  120.  
  121.         ASSERT_TRACE(number == t -> type_cnet,
  122.             es(ftag); es(":"); es(current_ftag); es(t -> type_name);
  123.             enl();
  124.             es("number: "); elong(number);
  125.             es(" != type_cnet"); elong(t -> type_cnet);
  126.         );
  127.     }
  128.     STATX(ftag);
  129. }
  130.  
  131. /*
  132.     Check the header and trailer areas.
  133.  
  134.     n is the size of the block *not* counting the header and trailer.
  135.     p is a pointer to the memory block, not the header.
  136. */
  137. static void
  138. obj_check_fill(char * p, long n, char * dtag)
  139. {
  140.     FTAG("obj_check_fill");
  141.     obj_head *    h = p2h(p);
  142.     char *        q;
  143.     int         i;
  144.     unsigned int val;
  145.     STATB(ftag);
  146.  
  147.     /* Check the header. */
  148.     for(i = 0; i < OBJ_HEADER_SIZE; i++) {
  149.         val = (h -> obj_prot[i]) & 0xff;
  150.  
  151.         ASSERT_TRACE(val == OBJ_FILLER,
  152.             obj_dump_fill(&(h->obj_prot[0]), OBJ_HEADER_SIZE, "Bad header\n");
  153.             es(ftag);  es(":"); es(current_ftag); es(":"); es(dtag); enl();
  154.             es(" p: "); eptr(p);
  155.             es(" n: "); elong(n);
  156.             es(" header byte "); eint(i); enl();
  157.             obj_dump_header(h, "");
  158.         );
  159.     }
  160.  
  161.     /* Check the trailer. */
  162.     for (q = p + n, i = 0; i < OBJ_TRAILER_SIZE; i++, q++) {
  163.         val = (*q) & 0xff;
  164.  
  165.         ASSERT_TRACE(val == OBJ_FILLER,
  166.             obj_dump_fill(p + n, OBJ_TRAILER_SIZE, "Bad trailer\n");
  167.             es(ftag); es(":"); es(current_ftag); es(":"); es(dtag); enl();
  168.             es(" p: "); eptr(p);
  169.             es(" n: "); elong(n);
  170.             es(" trailer byte "); eint(i); enl();
  171.             obj_dump_header(h, "");
  172.         );
  173.     }
  174.     STATX(ftag);
  175. }
  176.  
  177. /*
  178.     Make sure obj is a valid object.
  179. */
  180. void
  181. obj_check_object(void * obj)
  182. {
  183.     FTAG("obj_check_object");
  184.     obj_head * h;
  185.     obj_head * h2 = p2h(obj);
  186.     STATB(ftag);
  187.  
  188.     for (h = obj_all; h != NULL; h = h -> obj_olist) {
  189.  
  190.         /* Found. */
  191.         if (h == h2) {
  192.  
  193.             /* Check the header and trailer bytes. */
  194.             obj_check_fill( ((char *) h + sizeof(obj_head)),
  195.                 h -> obj_size, h -> obj_dtag);
  196.             STATX(ftag);
  197.             return;
  198.         }
  199.     }
  200.  
  201.     /* Not found. */
  202.     {
  203.         char buf [100];
  204.         err_fatal2("unallocated pointer: ", cvt_ptr(buf, 100, obj));
  205.     }
  206. }
  207.  
  208. /*
  209.     Print the fill area.
  210. */
  211. static void
  212. obj_dump_fill(char *p, int n, char * message)
  213. {
  214.     FTAG("obj_dump_fill");
  215.     int i;
  216.     unsigned int val;
  217.     STATB(ftag);
  218.  
  219.     ecnl(); enl(); es(message); enl();
  220.     for (i = 0; i < n; i++) {
  221.         val = (p[i]) & 0xff;
  222.         if (val == OBJ_FILLER) {
  223.             es("<FILL>");
  224.         }
  225.         else {
  226.             echar(p[i]); es("<"); ehexchar(p[i]); es(">");
  227.         }
  228.     }
  229.     enl();
  230.     STATX(ftag);
  231. }
  232.  
  233. /*
  234.     Dump the header of an object, given a pointer to the header.
  235. */
  236. static void
  237. obj_dump_header(obj_head * h, char * pad_string)
  238. {
  239.     FTAG("obj_dump_header");
  240.     char *        p = (char *) (((char *) h) + sizeof(obj_head));
  241.     type_des *    t = h -> obj_type;
  242.     int            attrib = t -> type_attrib;
  243.     STATB(ftag);
  244.     ASSERT(t -> type_name);
  245.  
  246.     /* Preceding a type name with a minus sign inhibits this dump. */
  247.     if (t -> type_name[0] != '-') {
  248.  
  249.         es(pad_string);
  250.         es("p: "); eptr(p);
  251.         es(" n: "); epadint(h -> obj_size, 5);
  252.         es(" "); es(h -> obj_dtag);
  253.         ecnl();
  254.     }
  255.  
  256.     STATX(ftag);
  257. }
  258.  
  259. /*
  260.     Dump all objects that have not been freed.
  261. */
  262. void
  263. obj_dump_objects(void)
  264. {
  265.     FTAG("obj_dump_objects");
  266.     STATB(ftag);
  267.  
  268.     {
  269.         register obj_head * h = obj_all;
  270.         while (h) {
  271.             obj_dump_header(h, "");
  272.             h = h -> obj_olist;
  273.         }
  274.     }
  275.  
  276.     STATX(ftag);
  277. }
  278.  
  279. /*
  280.     Dump the value of a single header, given a pointer to the object.
  281. */
  282. static void
  283. obj_dump_obj_header(void * obj, char * pad_string)
  284. {
  285.     FTAG("obj_dump_obj_header");
  286.     STATB(ftag);
  287.  
  288.     obj_dump_header(p2h(obj), pad_string);
  289.  
  290.     STATX(ftag);
  291. }
  292.  
  293. /*
  294.     Print all statistics alphabetically by type name.
  295. */
  296. void
  297. obj_dump_stats(void)
  298. {
  299.     FTAG("obj_dump_stats");
  300.     register type_des * t;
  301.     long ntot_width = 7;    /* These are the minimum widths of the columns. */
  302.     long nmax_width = 7;
  303.     long nnet_width = 7;
  304.     long ctot_width = 7;
  305.     long cmax_width = 7;
  306.     long cnet_width = 7;
  307.     char buf [CVT_BUF_SIZE];
  308.     STATB(ftag);
  309.  
  310.     /* Determine the widths of all columns. */
  311.     obj_max_tag_size = max(10, obj_max_tag_size);
  312.     
  313.     #if 0 /* Avoid sprintf so we don't pull in the whole floating library. */
  314.  
  315.         ntot_width    = max(ntot_width, 1 + sprintf(buf, "%ld", obj_ntot));
  316.         nmax_width    = max(nmax_width, 1 + sprintf(buf, "%ld", obj_nmax));
  317.         nnet_width    = max(nnet_width, 1 + sprintf(buf, "%ld", obj_nnet));
  318.         ctot_width    = max(ctot_width, 1 + sprintf(buf, "%ld", obj_ctot));
  319.         cmax_width    = max(cmax_width, 1 + sprintf(buf, "%ld", obj_cmax));
  320.         cnet_width    = max(cnet_width, 1 + sprintf(buf, "%ld", obj_cnet));
  321.         
  322.     #else
  323.     
  324.         ntot_width    = max(ntot_width, 1 + cvt_l2s(buf, obj_ntot));
  325.         nmax_width    = max(nmax_width, 1 + cvt_l2s(buf, obj_nmax));
  326.         nnet_width    = max(nnet_width, 1 + cvt_l2s(buf, obj_nnet));
  327.         ctot_width    = max(ctot_width, 1 + cvt_l2s(buf, obj_ctot));
  328.         cmax_width    = max(cmax_width, 1 + cvt_l2s(buf, obj_cmax));
  329.         cnet_width    = max(cnet_width, 1 + cvt_l2s(buf, obj_cnet));
  330.     
  331.     #endif
  332.     
  333.     ecnls(2);
  334.     
  335.     #if 0 /* Not used since these are user statistics. */
  336.         es(title); es(": Class statistics:\n\n");
  337.     #endif
  338.     
  339.     epads("TYPE NAME", obj_max_tag_size);
  340.     epads("ntot", ntot_width); epads("nmax", nmax_width); epads("nnet", nnet_width);
  341.     epads("ctot", ctot_width); epads("cmax", cmax_width); epads("cnet", cnet_width);
  342.     enl();
  343.  
  344.     for (t = obj_alpha; t != NULL; t = t -> type_alpha) {
  345.         epads(t -> type_name, obj_max_tag_size);
  346.         epadlong(t -> type_ntot, ntot_width);
  347.         epadlong(t -> type_nmax, nmax_width);
  348.         epadlong(t -> type_nnet, nnet_width);
  349.         epadlong(t -> type_ctot, ctot_width);
  350.         epadlong(t -> type_cmax, cmax_width);
  351.         epadlong(t -> type_cnet, cnet_width);
  352.         enl();
  353.     }
  354.  
  355.     epads("TOTALS", obj_max_tag_size);
  356.     epadlong(obj_ntot, ntot_width);
  357.     epadlong(obj_nmax, nmax_width);
  358.     epadlong(obj_nnet, nnet_width);
  359.     epadlong(obj_ctot, ctot_width);
  360.     epadlong(obj_cmax, cmax_width);
  361.     epadlong(obj_cnet, cnet_width);
  362.     enl();
  363.  
  364.     epads(" ", obj_max_tag_size);
  365.     epads("ntot", ntot_width); epads("nmax", nmax_width); epads("nnet", nnet_width);
  366.     epads("ctot", ctot_width); epads("cmax", cmax_width); epads("cnet", cnet_width);
  367.     enl();
  368.  
  369.     #if 0 /* Not used since these are user statistics. */
  370.         es("obj_ntypes: "); elong(obj_ntypes); enl();
  371.         es("obj_num_strcmp: "); elong(obj_num_strcmp); enl();
  372.     #endif
  373.  
  374.     obj_check_all();
  375.  
  376.     STATX(ftag);
  377. }
  378.  
  379. /*
  380.     Find the type descriptor corresponding to a tag.
  381.     Create a new type descriptor if necessary.
  382.  
  383.     This lookup may be very slow because this routine is only called once
  384.     per each instance of a call to obj_new_db in the text.
  385. */
  386. static type_des *
  387. obj_find_type (char * tag)
  388. {
  389.     FTAG("obj_find_type");
  390.     register type_des * t = NULL;
  391.     register type_des * t_prev = NULL;
  392.     STATB(ftag);
  393.  
  394.     /* Search the alphabetical list of types. */
  395.     for (t_prev = NULL, t = obj_alpha; t; t_prev = t, t = t -> type_alpha) {
  396.         int n = strcmp(tag, t -> type_name);
  397.         obj_num_strcmp++;
  398.         if (n == 0) {
  399.             goto found;
  400.         }
  401.         if (n < 0) {
  402.             goto not_found;
  403.         }
  404.     }
  405.  
  406. not_found:
  407.  
  408.     /* Set obj_max_tag_size */
  409.     {
  410.         size_t tag_size = strlen(tag);
  411.         obj_max_tag_size = max(tag_size, obj_max_tag_size);
  412.     }
  413.  
  414.     /* Create a new type descriptor. */
  415.     t = obj_new(sizeof(type_des));
  416.     t -> type_name        = tag;
  417.     t -> type_magic     = OBJ_MAGIC;
  418.     obj_ntypes++;
  419.  
  420.     /* Link the type descriptor into the alphabetical list. */
  421.     if (t_prev == NULL) {
  422.  
  423.         /* Link it before the first node. */
  424.         t -> type_alpha = obj_alpha;    /* Bug fix: 11/6/93 */
  425.         obj_alpha = t;
  426.     }
  427.     else {
  428.         ASSERT(obj_alpha);
  429.         t -> type_alpha = t_prev -> type_alpha;
  430.         t_prev -> type_alpha = t;
  431.     }
  432.  
  433.     TRACEPX(ftag, es(" name: "); es(tag); enl());
  434.     return t;
  435.  
  436. found:
  437.     STATX(ftag);
  438.     return t;
  439. }
  440.  
  441. /*
  442.     Check to make sure the object is on the object list for its type.
  443.     If found:
  444.     • remove the object from the list of allocated nodes.
  445.     • Update the net statistics for the object.
  446. */
  447. static void
  448. obj_free_check(void * p)
  449. {
  450.     FTAG("obj_free_check");
  451.     obj_head * h, * h2, * h3;
  452.     type_des * t;
  453.     STATB(ftag);
  454.     ASSERT_TRACE(p, es(": NULL object"));
  455.  
  456.     h = p2h(p);
  457.     t = h -> obj_type;
  458.  
  459.     ASSERT_TRACE(t, es(": NULL type"); obj_dump_obj_header(p, "*"));
  460.     ASSERT_TRACE(obj_all, es(": NULL obj_all"));
  461.  
  462.     /* Remove the node from the list of all allocated nodes. */
  463.     if (obj_all == h) {
  464.         obj_all = h -> obj_olist;
  465.         goto found1;
  466.     }
  467.     for (    h2 = obj_all, h3 = h2 -> obj_olist;
  468.             h3 != NULL;
  469.             h2 = h3, h3 = h2 -> obj_olist
  470.         ) {
  471.         if (h3 == h) {
  472.             /* Remove h3. */
  473.             h2 -> obj_olist = h3 -> obj_olist;
  474.             goto found1;
  475.         }
  476.     }
  477.  
  478.     /*
  479.         It is often useful to pretend it *is* on the list for dump purposes.
  480.     */
  481.     {
  482.         char buf [100];
  483.         err_fatal2("object not on object list: ", cvt_ptr(buf, 100, p));
  484.     }
  485.  
  486. found1:
  487.  
  488.     ASSERT_TRACE(t -> type_tlist,
  489.         es(": NULL type_tlist");
  490.         obj_dump_obj_header(p, "*");
  491.     );
  492.  
  493.     /* Remove the node from the list of nodes of a particular type. */
  494.     if (t -> type_tlist == h) {
  495.         t -> type_tlist = h -> obj_tlist;
  496.         goto found2;
  497.     }
  498.     for (    h2 = t -> type_tlist, h3 = h2 -> obj_tlist;
  499.             h3 != NULL;
  500.             h2 = h3, h3 = h2 -> obj_tlist
  501.         ) {
  502.         if (h3 == h) {
  503.             /* Remove h3. */
  504.             h2 -> obj_tlist = h3 -> obj_tlist;
  505.             goto found2;
  506.         }
  507.     }
  508.     {
  509.         char buf [100];
  510.         err_fatal2("object not on type's object list: ", cvt_ptr(buf,100, p));
  511.     }
  512.  
  513. found2:
  514.  
  515.     /* Reduce the net statistics. */
  516.     t -> type_nnet -= h -> obj_size;
  517.     obj_nnet -= h -> obj_size;
  518.     t -> type_cnet--;
  519.     obj_cnet--;
  520.  
  521.     STATX(ftag);
  522. }
  523.  
  524. /*
  525.     Free a block of memory allocated by obj_alloc.
  526.     p must point to the logical block, *not* the header.
  527. */
  528. void
  529. obj_free_db(void * obj)
  530. {
  531.     FTAG("obj_free_db");
  532.     obj_head * h = p2h(obj);
  533.     STATB(ftag);
  534.     ASSERT(obj);
  535.  
  536.     obj_free_check(obj);
  537.     TRACE("obj_v", obj_check_all());
  538.  
  539.     /*
  540.         free() may "corrupt" the object;
  541.         make sure to print the object *before* freeing it.
  542.     */
  543.     TRACEP(ftag, obj_dump_obj_header(obj, "*"));
  544.     
  545.     TRACEN("-obj_watch",
  546.             sl_unwatch(&(h -> obj_prot[0]), OBJ_HEADER_SIZE);
  547.             sl_unwatch( ((char *)obj) + (h -> obj_size), OBJ_TRAILER_SIZE);
  548.     );
  549.     
  550.     lib_free(h);
  551.     TRACEPX(ftag, es("lib_free("); eptr(h); es(")\n"));
  552. }
  553.  
  554. #endif /* n PRODUCTION */
  555.  
  556. /*
  557.     Return a block of zeroed memory and abort if not enough memory is available.
  558. */
  559. void *
  560. obj_new(size_t n)
  561. {
  562.     FTAG("obj_new");
  563.     char * p;
  564.     STATB(ftag);
  565.  
  566.     /* Align the request. */
  567.     if (n & 1) {
  568.         n++;
  569.     }
  570.  
  571.     p = lib_calloc((size_t) 1, (size_t) n);
  572.  
  573. #ifdef PRODUCTION_TRACE
  574.     ecnl(); es(ftag);
  575.     es(" n: "); elong(n);
  576.     es(" p: "); eptr(p); enl();
  577. #endif
  578.  
  579.     if (p == NULL) {
  580.         char buf [CVT_BUF_SIZE];
  581.         err_fatal3(
  582.             "Sorry, can not allocate ",
  583.             cvt_int(buf, CVT_BUF_SIZE, n),
  584.             " bytes");
  585.     }
  586.  
  587.     TRACEPX(ftag, eret(); eptr(p); es(" = lib_calloc(1, "); elong(n); es(")\n"));
  588.     return p;
  589. }
  590.  
  591. /*
  592.     Debugging version of obj_new.
  593. */
  594. #ifndef PRODUCTION
  595.  
  596. void *
  597. obj_new_db(size_t n, char * tag, type_des ** tp)
  598. {
  599.     FTAG("obj_new_db");
  600.     register char *        p;    /* Pointer to logical object. */
  601.     register obj_head *    h;    /* Pointer to object header. */
  602.     register type_des * t;    /* Pointer to object's type descriptor. */
  603.  
  604.     STATB(ftag);
  605.  
  606.     /* All fields are protected. */
  607.     h = obj_new(n + sizeof(obj_head) + OBJ_TRAILER_SIZE);
  608.  
  609.     p = (((char *) h) + sizeof(obj_head));
  610.  
  611.     if (*tp == NULL) {
  612.         *tp = obj_find_type(tag);
  613.     }
  614.     t = *tp;
  615.  
  616.     /* Fill in the fields of the header. */
  617.     h -> obj_type = t;
  618.     h -> obj_dtag = tag;
  619.     h -> obj_tlist = t -> type_tlist;
  620.     t -> type_tlist = h;
  621.     h -> obj_olist = obj_all;
  622.     obj_all = h;
  623.     h -> obj_size = n;
  624.  
  625.     /* Update the staticstics fields in the type descriptor. */
  626.     t -> type_cnet++;
  627.     t -> type_cmax = max(t -> type_cmax, t -> type_cnet);
  628.     t -> type_ctot++;
  629.  
  630.     t -> type_nnet += (long) n;
  631.     t -> type_nmax = max(t -> type_nmax, t -> type_nnet);
  632.     t -> type_ntot += (long) n;
  633.  
  634.     obj_cnet++;
  635.     obj_cmax = max(obj_cmax, obj_cnet);
  636.     obj_ctot++;
  637.  
  638.     obj_nnet += (long) n;
  639.     obj_nmax = max(obj_nmax, obj_nnet);
  640.     obj_ntot += (long) n;
  641.  
  642.     /* Fill in the header and trailer protection fields. */
  643.     {
  644.         register int i;
  645.         register char * q;
  646.         for(i = 0; i < OBJ_HEADER_SIZE; i++) {
  647.             h -> obj_prot[i] = OBJ_FILLER;
  648.         }
  649.         for (q = p + n, i = 0; i < OBJ_TRAILER_SIZE; i++) {
  650.             *q++ = OBJ_FILLER;
  651.         }
  652.         
  653.         TRACEN("-obj_watch",
  654.             sl_watch(&(h -> obj_prot[0]), OBJ_HEADER_SIZE, "obj header");
  655.             sl_watch(p + n, OBJ_TRAILER_SIZE, "obj trailer");
  656.         );
  657.     }
  658.  
  659.     TRACEN("obj_v", obj_check_all());
  660.  
  661.     TRACEPX(ftag, epadlong(n,4); eblank(); eret(); eptr(p);
  662.     eblank(); es(t -> type_name); enl());
  663.     return p;
  664. }
  665.  
  666. /*
  667.     Test this module for blunders.
  668.     Memory allocation stress test.
  669. */
  670. #define MAX_IT    50
  671. #define MAX_OBJ 10
  672. #define OBJ_SIZE 50
  673.  
  674. #define MAX_ITEMS 12
  675. #define ITEM_SIZE 20
  676. #define ITEM_PER_BLOCK 5
  677.  
  678. static char * objects [MAX_OBJ];
  679.  
  680. /*
  681.     A test to see whether obj_free_db really is freeing memory.
  682. */
  683. void
  684. obj_test (void)
  685. {
  686.     FTAG("obj_test");
  687.     FTAGV("-obj_test_v");
  688.     register int i, j;
  689.     static type_des * otype = NULL;
  690.     STATB(ftag);
  691.  
  692.     ecnl(); enl();
  693.     es("obj_test: start of allocation test\n\n");
  694.     env_dump_stats();
  695.  
  696.     /* Start loops at 1 so we do not request 0 bytes. */
  697.     for (i = 1; i < MAX_IT; i++) {
  698.         for (j = 1; j < MAX_OBJ; j++) {
  699.             type_des * tp = NULL;
  700.             objects [j] = obj_new_db(OBJ_SIZE * j * i, "object_test_type", &tp);
  701.         }
  702.         for (j = 1; j < MAX_OBJ; j++) {
  703.             obj_free_db(objects [j]);
  704.         }
  705.         es("End of iteration "); eint(i); enl();
  706.     }
  707.  
  708.     TRACEP(ftagv, sl_off("obj_*"); sl_on("obj_v"));
  709.  
  710.     es("Allocation test complete\n\n");
  711.     env_dump_stats();
  712.  
  713.     STATX(ftag);
  714. }
  715.  
  716. #endif /* n PRODUCTION */
  717.